package org.helgoboss.code_meta_data_extractor

class MetaDataNotFoundException extends Exception
class MetaDataFormatException(message: String) extends Exception(message)

import org.helgoboss.scala_slf4j._

class CodeMetaDataExtractor(trigger: String) extends Slf4jLogging {
    
    @throws(classOf[MetaDataNotFoundException])
    @throws(classOf[MetaDataFormatException])
    def extractMetaData(code: String): Map[String, Any] = new ProjectMapParser(trigger).parseFromBeginning(code)
    
    private class ProjectMapParser(trigger: String) extends util.parsing.json.Parser {        
        def parseFromBeginning(code: String) = {
            val multilineEnabled = "(?s)"
            val anything = """.*?"""
            val anythingGreedy = """.*"""
            val star = """\*"""
            val leftBrace = """\{"""
            val commentStart = "/" + star
            val space = " "
            def group(s: String) = "(" + s + ")"
            
            val regex = (multilineEnabled + commentStart + anything + trigger + space + group(leftBrace + anythingGreedy)).r
            
            regex.findFirstMatchIn(code) match {
                case Some(m) => 
                    val jsonWithNastyStars = m.group(1)
                    val jsonWithoutNastyStars = jsonWithNastyStars.replaceAll(star, "")
                    parseFromLeftBrace(jsonWithoutNastyStars)
                    
                case None =>
                    throw new MetaDataNotFoundException
            }
        }
        
        def parseFromLeftBrace(remainingCode: String) = jsonObj(new lexical.Scanner(remainingCode)) match {
            case Success(result, _) => util.parsing.json.JSON.resolveType(result).asInstanceOf[Map[String, Any]]
            case failureOrError @ _ => throw new MetaDataFormatException(failureOrError.toString)
        }
    }
}